package org.goldenport.g3.messages.scalatest

import org.scalatest.matchers.{BeMatcher, MatchResult}
import org.goldenport.g3.messages._
import org.scalatest.matchers.Matcher
import org.scalatest.TestFailedException

/**
 * @since   Jul.  1, 2011
 * @version Jul.  3, 2011
 * @author  ASAMI, Tomoharu
 */
trait RecordMatchers {
  def record(r: Record) = RecordBeMatcher(r)
  def record(r: Tuple2[Symbol, Any]*) = RecordBeMatcher(r: _*)
  def record(r: String) = RecordBeMatcher(r)

  implicit def convertToRecordShouldWrapper(r: Record): RecordShouldWrapper = new RecordShouldWrapper(r)

  final class RecordShouldWrapper(left: Record) {
    def should(rightMatcher: Matcher[Record]) {
      rightMatcher(left) match {
        case MatchResult(false, failureMessage, _, _, _) => throw new TestFailedException(failureMessage, 10)
        case _ => ()
      }
    }
  }
/*
    def should(notWord: NotWord): ResultOfNotWordForInt = {
      new ResultOfNotWordForInt(left, false)
    }*/
}

object RecordMatchers extends RecordMatchers

class RecordBeMatcher(val record: Record) extends BeMatcher[Record] {
  override def apply(r: Record): MatchResult = {
    val ctx: RecordContext = new PlainRecordContext

    def _is_equal(name: Symbol, lhs: AnyRef, rhs: AnyRef): Boolean = {
      val rso: Option[RecordSchema] = record.schema orElse r.schema
      rso match {
        case Some(s) => s.getField(name) match {
          case Some(rf) => rf.normalize(rhs, ctx) == rf.normalize(lhs, ctx)
        }
        case None => rhs.toString == lhs.toString 
      }
    }
    
    val msgs: List[String] = (for ((fk, fv) <- record.fields.toList) yield {
      r.get(fk) match {
        case Some(v) => {    
          if (_is_equal(fk, fv, v)) None else Some("%s is %s not %s".format(fk.name, v, fv))
        }
        case None => Some("%s is missing".format(fk.name))
      }
    }).flatten
    new MatchResult(msgs.isEmpty,
        "Record was not match due to " + msgs.mkString(","),
        "Reocrd was match")
  }
}

object RecordBeMatcher {
  def apply(r: Record) = new RecordBeMatcher(r)
  def apply(r: Tuple2[Symbol, Any]*) = new RecordBeMatcher(Record(r: _*))
  def apply(r: String) = new RecordBeMatcher(Record(r))
}
